package com.gzc.just.play.last.war.allinone.orchestration;

import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 服务器依赖关系图
 * 定义各服务器的启动顺序和依赖规则
 */
@Component
public class ServerDependencyGraph {
    
    private final Map<ServerType, Set<ServerType>> dependencies = new HashMap<>();
    private final Map<ServerType, Set<ServerType>> dependents = new HashMap<>();
    
    /**
     * 初始化依赖关系图
     */
    public ServerDependencyGraph() {
        initializeDependencies();
    }
    
    /**
     * 初始化服务器依赖关系
     * 
     * 依赖关系说明：
     * 1. LoginServer - 无依赖，最先启动
     * 2. BalanceServer - 无依赖，可与LoginServer并行启动
     * 3. CentralServer - 依赖LoginServer和BalanceServer
     * 4. GateServer - 依赖CentralServer
     * 5. SceneServer - 依赖CentralServer
     */
    private void initializeDependencies() {
        // LoginServer - 无依赖
        addDependency(ServerType.LOGIN_SERVER);
        
        // BalanceServer - 无依赖
        addDependency(ServerType.BALANCE_SERVER);
        
        // CentralServer - 依赖LoginServer和BalanceServer
        addDependency(ServerType.CENTRAL_SERVER, ServerType.LOGIN_SERVER, ServerType.BALANCE_SERVER);
        
        // GateServer - 依赖CentralServer
        addDependency(ServerType.GATE_SERVER, ServerType.CENTRAL_SERVER);
        
        // SceneServer - 依赖CentralServer
        addDependency(ServerType.SCENE_SERVER, ServerType.CENTRAL_SERVER);
    }
    
    /**
     * 添加依赖关系
     * @param serverType 服务器类型
     * @param requiredServers 依赖的服务器列表
     */
    private void addDependency(ServerType serverType, ServerType... requiredServers) {
        Set<ServerType> serverDeps = new HashSet<>();
        for (ServerType requiredServer : requiredServers) {
            serverDeps.add(requiredServer);
            
            // 更新被依赖服务器的依赖者列表
            dependents.computeIfAbsent(requiredServer, k -> new HashSet<>()).add(serverType);
        }
        
        dependencies.put(serverType, serverDeps);
        
        // 确保所有服务器都在dependents映射中
        dependents.computeIfAbsent(serverType, k -> new HashSet<>());
    }
    
    /**
     * 获取指定服务器的依赖列表
     * @param serverType 服务器类型
     * @return 依赖的服务器列表
     */
    public Set<ServerType> getDependencies(ServerType serverType) {
        return dependencies.getOrDefault(serverType, Collections.emptySet());
    }
    
    /**
     * 获取依赖指定服务器的服务器列表
     * @param serverType 服务器类型
     * @return 依赖该服务器的服务器列表
     */
    public Set<ServerType> getDependents(ServerType serverType) {
        return dependents.getOrDefault(serverType, Collections.emptySet());
    }
    
    /**
     * 检查服务器是否可以启动
     * @param serverType 服务器类型
     * @param serverStates 当前服务器状态
     * @return 是否可以启动
     */
    public boolean canStart(ServerType serverType, Map<ServerType, ServerState> serverStates) {
        Set<ServerType> requiredServers = getDependencies(serverType);
        
        for (ServerType requiredServer : requiredServers) {
            ServerState state = serverStates.get(requiredServer);
            if (state == null || 
                !(state == ServerState.READY || state == ServerState.CONNECTED || state == ServerState.RUNNING)) {
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 获取按照依赖关系排序的服务器启动顺序
     * @return 启动顺序列表
     */
    public List<ServerType> getStartupOrder() {
        List<ServerType> startupOrder = new ArrayList<>();
        Set<ServerType> visited = new HashSet<>();
        
        // 使用拓扑排序确定启动顺序
        for (ServerType serverType : ServerType.values()) {
            if (!visited.contains(serverType)) {
                topologicalSort(serverType, visited, startupOrder);
            }
        }
        
        return startupOrder;
    }
    
    /**
     * 拓扑排序辅助方法
     * @param serverType 当前服务器类型
     * @param visited 已访问集合
     * @param startupOrder 启动顺序列表
     */
    private void topologicalSort(ServerType serverType, Set<ServerType> visited, List<ServerType> startupOrder) {
        if (visited.contains(serverType)) {
            return;
        }
        
        // 先处理所有依赖
        for (ServerType dependency : getDependencies(serverType)) {
            if (!visited.contains(dependency)) {
                topologicalSort(dependency, visited, startupOrder);
            }
        }
        
        visited.add(serverType);
        startupOrder.add(serverType);
    }
    
    /**
     * 获取可以并行启动的服务器组
     * @return 服务器组列表，每组内的服务器可以并行启动
     */
    public List<List<ServerType>> getParallelGroups() {
        List<List<ServerType>> groups = new ArrayList<>();
        Set<ServerType> assigned = new HashSet<>();
        
        List<ServerType> startupOrder = getStartupOrder();
        
        int i = 0;
        while (i < startupOrder.size()) {
            List<ServerType> currentGroup = new ArrayList<>();
            
            for (int j = i; j < startupOrder.size(); j++) {
                ServerType serverType = startupOrder.get(j);
                
                // 检查是否所有依赖都已经在之前的组中
                boolean canInclude = true;
                for (ServerType dependency : getDependencies(serverType)) {
                    if (!assigned.contains(dependency)) {
                        canInclude = false;
                        break;
                    }
                }
                
                if (canInclude && !assigned.contains(serverType)) {
                    currentGroup.add(serverType);
                }
            }
            
            // 如果当前组为空，说明存在循环依赖，使用备用逻辑
            if (currentGroup.isEmpty() && i < startupOrder.size()) {
                currentGroup.add(startupOrder.get(i));
            }
            
            groups.add(currentGroup);
            assigned.addAll(currentGroup);
            i += currentGroup.size();
        }
        
        return groups;
    }
    
    /**
     * 获取依赖关系图的文本表示
     * @return 依赖关系图文本
     */
    public String getDependencyGraphString() {
        StringBuilder sb = new StringBuilder();
        sb.append("Server Dependency Graph:\n");
        
        for (ServerType serverType : ServerType.values()) {
            sb.append(serverType.getName()).append(" -> ");
            
            Set<ServerType> deps = getDependencies(serverType);
            if (deps.isEmpty()) {
                sb.append("(no dependencies)");
            } else {
                sb.append(deps.stream()
                        .map(ServerType::getName)
                        .collect(Collectors.joining(", ")));
            }
            
            sb.append("\n");
        }
        
        return sb.toString();
    }
}